#pragma once

#include <QObject>
#include <QByteArray>
#include <QDateTime>
#include <QElapsedTimer>
#include <functional>
#include <memory>
#include "infrastructure/io/tcp_socket_client.h"
#include "kernel/interfaces/ILogger.h"

namespace application {
namespace caller {

/**
 * @brief 呼叫器协议错误码
 */
enum class ProtocolError {
    OK = 0,
    OVER_TIME = 1,
    FORMAT_ERROR = 2,
};

using protocol_cb_t = std::function<void(QByteArray&)>;

/**
 * @brief 呼叫器协议类
 * @details 处理呼叫器TCP通信协议
 */
class CallerProtocol : public QObject {
    Q_OBJECT

public:
    explicit CallerProtocol(std::shared_ptr<kernel::ILogger> logger = nullptr, QObject* parent = nullptr);
    explicit CallerProtocol(infrastructure::io::TcpSocketClient* tcpClient,
                           std::shared_ptr<kernel::ILogger> logger = nullptr,
                           QObject* parent = nullptr);
    ~CallerProtocol() = default;

    /**
     * @brief 初始化TCP连接
     */
    bool initTcpConnection(const QHostAddress& address, quint16 port);

    /**
     * @brief 写TCP数据
     */
    bool writeTcpData(const QByteArray& sendData, protocol_cb_t callback = nullptr);

    /**
     * @brief 获取协议状态
     */
    qint64 getProtocolState() const;

    /**
     * @brief 设置数据接收回调
     */
    void setAnalyzeCallbackFunc(protocol_cb_t callback);

    /**
     * @brief 获取TCP客户端指针
     */
    infrastructure::io::TcpSocketClient* getTcpClient() { return m_tcpConnection; }

    QDateTime datetime;  // 记录最后收到数据的时间

private slots:
    void receiveTcpReadyRead();

private:
    infrastructure::io::TcpSocketClient* m_tcpConnection = nullptr;
    protocol_cb_t m_receiveFinishCallback = nullptr;
    ProtocolError m_status = ProtocolError::OK;
    QByteArray m_messageCache;
    QByteArray m_lastMessage;  // 存放所有读取的数据
    QElapsedTimer m_elapsedTime;  // 用来监测时间
    QString m_lastError;
    int m_timeout = 3000;
    std::shared_ptr<kernel::ILogger> m_logger;
};

/**
 * @brief 呼叫器消息结构
 */
struct CallerMessage {
    bool taskManagerHandle;  // true为已被任务管理器挂起，需要进行处理
    QString taskName;        // 任务名称
    uint8_t randNum;         // 随机数
    CallerProtocol* protocol;  // 协议指针
};

} // namespace caller
} // namespace application
